package com.isoft.illustrationsdraw.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


import org.springframework.stereotype.Service;

import com.isoft.illustrationsdraw.brief.BriefIllustrationInfo;
import com.isoft.illustrationsdraw.brief.BriefUserInfo;
import com.isoft.illustrationsdraw.dto.IllustrationDetailDTO;
import com.isoft.illustrationsdraw.dto.NewIllustrationDTO;
import com.isoft.illustrationsdraw.dto.TagDTO;
import com.isoft.illustrationsdraw.entity.Illustration;
import com.isoft.illustrationsdraw.entity.IllustrationCollection;
import com.isoft.illustrationsdraw.entity.IllustrationTag;
import com.isoft.illustrationsdraw.entity.Tag;
import com.isoft.illustrationsdraw.entity.User;
import com.isoft.illustrationsdraw.entity.Comment;
import com.isoft.illustrationsdraw.entity.Follow;
import com.isoft.illustrationsdraw.entity.LikeIllustration;

import com.isoft.illustrationsdraw.service.IllustrationCollectionService;
import com.isoft.illustrationsdraw.service.IllustrationDTOService;
import com.isoft.illustrationsdraw.service.IllustrationService;
import com.isoft.illustrationsdraw.service.IllustrationTagService;
import com.isoft.illustrationsdraw.service.JWTService;

import com.isoft.illustrationsdraw.service.FileService;
import com.isoft.illustrationsdraw.service.FollowService;
import com.isoft.illustrationsdraw.service.SubLevelService;
import com.isoft.illustrationsdraw.service.UserService;
import com.isoft.illustrationsdraw.service.AdminService;
import com.isoft.illustrationsdraw.service.CommentService;
import com.isoft.illustrationsdraw.service.TagService;
import com.isoft.illustrationsdraw.service.UserDTOService;
import com.isoft.illustrationsdraw.dto.CommentDTO;
import com.isoft.illustrationsdraw.service.LikeIllustrationService;
import com.isoft.illustrationsdraw.service.LikeTagService;
import com.isoft.illustrationsdraw.service.SearchService;

@Service
public class IllustrationDTOServiceImpl implements IllustrationDTOService {

    private final IllustrationService illustrationService;
    private final IllustrationCollectionService illustrationCollectionService;
    // private final TagService tagService;
    private final IllustrationTagService illustrationTagService;
    private final CommentService commentService;
    private final UserService userService;
    private final SubLevelService subLevelService;
    private final JWTService jwtService;
    private final TagService tagService;
    private final AdminService adminService;
    private final FollowService followService;
    private final FileService fileService;
    private final LikeIllustrationService likeIllustrationService;
    private final LikeTagService likeTagService;
    private final SearchService searchService;
    private final UserDTOService userDTOService;
   
    public IllustrationDTOServiceImpl(UserDTOService userDTOService, IllustrationService illustrationService, IllustrationCollectionService illustrationCollectionService, IllustrationTagService illustrationTagService, CommentService commentService, UserService userService, SubLevelService subLevelService, JWTService jwtService, TagService tagService, AdminService adminService, FileService fileService, LikeIllustrationService likeIllustrationService, FollowService followService, LikeTagService likeTagService, SearchService searchService) {
        this.illustrationService = illustrationService;
        this.illustrationCollectionService = illustrationCollectionService;
        this.illustrationTagService = illustrationTagService;
        this.commentService = commentService;
        this.userService = userService;
        this.subLevelService = subLevelService;
        this.jwtService = jwtService;
        this.tagService = tagService;
        this.adminService = adminService;
        this.fileService = fileService;
        this.likeIllustrationService = likeIllustrationService;
        this.followService = followService;
        this.likeTagService = likeTagService;
        this.searchService = searchService;
        this.userDTOService = userDTOService;
    }

    @Override
    public IllustrationDetailDTO attemptGetIllustrationDetailDTO(Long illustrationId, String token) {
        Long userId = jwtService.getUserIdFromToken(token);
        if (!checkIfIllustrationCanBeAccessed(illustrationId, userId)) {
            return null;
        }


        return getIllustrationDetailDTO(illustrationId, userId);
    }

    @Override
    public boolean addLikeIllustration(LikeIllustration likeIllustration) {

        return likeIllustrationService.save(likeIllustration);

    }

    @Override
    public boolean checkIfIllustrationCanBeAccessed(Long illustrationId, Long userId) {
        // 获取插画信息
        Illustration illustration = illustrationService.getById(illustrationId);
    
        // 检查插画是否存在
        if (illustration == null) {
            return false;
        }

        boolean isAdmain = adminService.getById(userId) != null;
        if (isAdmain) {
            return true;
        }
    
        // 获取订阅级别
        var t = subLevelService.getSublevel(userId, illustration.getAuthorId());
        Integer subLevel = t == null ? 0 : t.getSubscriptionLevel();
    

        // 检查可见性和订阅级别
        if (illustration.getVisibility() == -1) {
            // 任何人不可见
            return false;
        } else if (illustration.getVisibility() == 0 && userId != illustration.getAuthorId()) {
            return false;
        } else if (subLevel != null && illustration.getVisibility() != 1 && subLevel < illustration.getVisibility() -1 && !userId.equals(illustration.getAuthorId())) {
            return false;
        }
    
        return true;
    }

    @Override
    public Long addNewIllustrationBaseInfo(Long userId, NewIllustrationDTO newIllustrationDTO) throws RuntimeException {

        Illustration illustration = new Illustration();
        illustration.setAuthorId(userId);
        illustration.setTitle(newIllustrationDTO.getTitle());
        illustration.setDescription(newIllustrationDTO.getDescription());
        illustration.setVisibility(newIllustrationDTO.getVisibility());
        illustrationService.save(illustration);
        Long illustrationId = illustration.getId();

        if (illustrationId == null) {
            throw new RuntimeException();
        }
        
        List<Long> tagIds = new ArrayList<>();
        for (var tag : newIllustrationDTO.getTags()) {
            Long tagId = tagService.getTagIdByName(tag);
            if (tagId == null) {
                var newTag = new Tag();
                newTag.setName(tag);
                tagService.save(newTag);
                tagId = newTag.getId();
            }
            tagIds.add(tagId);
        }

        for (int i=0; i < newIllustrationDTO.getTags().size(); i++) {
            IllustrationTag illustrationTag = new IllustrationTag();
            illustrationTag.setIllustrationsId(illustrationId);
            illustrationTag.setTagId(tagIds.get(i));
            illustrationTag.setTagName(newIllustrationDTO.getTags().get(i));
            illustrationTagService.save(illustrationTag);
        }


        return illustrationId;        
    }

    @Override
    public void addNewIllustrationCollection(Long illustrationId, List<String> paths) {
        for (int i=0; i < paths.size(); i++) {
            IllustrationCollection illustrationCollection = new IllustrationCollection();
            illustrationCollection.setIllustrationsId(illustrationId);
            illustrationCollection.setOrderIndex(i);
            illustrationCollection.setImageUrl(paths.get(i));
            illustrationCollectionService.save(illustrationCollection);
        }
    }
    
    private IllustrationDetailDTO getIllustrationDetailDTO(Long id, Long userId) {

        // 数据库插画信息
        Illustration illustration = illustrationService.getById(id);
        // 数据库插画集合信息
        List<IllustrationCollection> illustrationCollection = illustrationCollectionService.getCollectionByIllustrationId(id);
        // 数据库插画标签信息
        List<IllustrationTag> illustrationTags = illustrationTagService.getTagsByIllustrationId(id);
        // 作者头像
        var localProfileImgUrl = userService.getById(illustration.getAuthorId()).getProfileImg();
        var profileImgUrl = localProfileImgUrl == null ? null : fileService.convertToOnlinePath(localProfileImgUrl);

        // 作者基本信息
        BriefUserInfo author = new BriefUserInfo(illustration.getAuthorId(), userService.getById(illustration.getAuthorId()).getNickname(), profileImgUrl);
        List<String> tagList = new ArrayList<String>();
        
        //Map<Integer, String> collectionMap = new HashMap<Integer, String>();
        List<Comment> comments = commentService.getCommentsByIllustrationId(id);
        List<CommentDTO> commentList = new ArrayList<CommentDTO>();
        // List<Resource> resources = resourceService.getIllustrationResourceById(id);
        List<String> collection = new ArrayList<String>();

        for (var everyIllustration : illustrationCollection) {
            collection.add(fileService.convertToOnlinePath(everyIllustration.getImageUrl()));
        }


        for (var illustrationTag : illustrationTags) {
            var tag = illustrationTag.getTagName();
            tagList.add(tag);
        }


        for (var comment : comments) {
            var commenterId = comment.getUserId();
            var commenterName = userService.getById(commenterId).getNickname();
            var t = userService.getById(userId).getProfileImg();
            var commenterProfileImg = t == null ? null : fileService.convertToOnlinePath(t);
            var commentId = comment.getId();
            var commentContent = comment.getContent();
            var commentCreatedAt = comment.getCreatedAt();
            var CommentDTO = new CommentDTO(commentId, comment.getIllustrationsId(), commentContent, commentCreatedAt, commenterId, commenterName, commenterProfileImg);
            commentList.add(CommentDTO);
        }

        boolean isLiked = likeIllustrationService.findLikeIllustration(userId, id) == null ? false : true;

        var t = new Follow();
        t.setFollowerId(userId);
        t.setFollowedId(author.getId());

        boolean isFollowed = followService.findFollow(t) == null ? false : true;

        IllustrationDetailDTO result = new IllustrationDetailDTO(
            illustration,   // Illustration
            author,         // BriefUserInfo
            collection,     // List<String>
            tagList,        // List<String>
            commentList,     // List<Map<CommentDTO, CommentDTO>>
            isLiked,
            isFollowed
        );

        return result;
    }

    @Override
    public boolean removeLikeIllustration(LikeIllustration likeIllustration) {
        var result = likeIllustrationService.findLikeIllustration(likeIllustration.getUserId(), likeIllustration.getIllustrationId());
        if (result != null) {
            return likeIllustrationService.removeById(likeIllustration.getId());
        }
        return false;
    }

    @Override
    public List<Tag> getRecommandTag(Long userId) {
        var likeTag = likeTagService.getLikeTagsByUser(userId);
        if (likeTag.size() < 20) {
            Integer limit = 30 - likeTag.size();
            var excludeIds = new ArrayList<Long>();
            for (var tag : likeTag) {
                excludeIds.add(tag.getId());
            }
            var result = new ArrayList<Tag>();

            for (var i : likeTag) {
                result.add(tagService.getById(i.getTagId()));
            }
            var randomList = tagService.getRandomTagsExcluding(excludeIds, limit);
            
            for (int i = 0; i < randomList.size(); ++i) {
                result.add(randomList.get(i));
            }
            return result;

        } else {
            var middleList = likeTag.subList(0, 20);
            var excludeIds = new ArrayList<Long>();
            var result = new ArrayList<Tag>();
            
            for (int i = 0; i<20; ++i) {
                excludeIds.add(middleList.get(i).getTagId());
                result.add(tagService.getById(middleList.get(i).getTagId()));
            }

            var randomList = tagService.getRandomTagsExcluding(excludeIds, 10);

            for (int i = 0; i<randomList.size(); ++i) {
                result.add(randomList.get(i));
            }
            return result;
        }
    }

    @Override
    public TagDTO getTagAndWork(Long userId, Long tagId, Integer page) {
        var tag = tagService.getById(tagId);
        var searchResult = searchService.searchIllustrationByTag(userId, null, tag.getId(), page);
        var result = new TagDTO(tag, searchResult);
        return result;
    }
    @Override
    public List<TagDTO> initTagAndWork(Long userId) {
        var tagList = getRecommandTag(userId);
        Collections.shuffle(tagList);

        var result = new ArrayList<TagDTO>();
        for (int i = 0; i < 5; ++i) {
            result.add(new TagDTO(tagList.get(i), searchService.searchIllustrationByTag(userId, null, tagList.get(i).getId(), 1)));
        }
        return result;
    }

    @Override
    public List<BriefIllustrationInfo> getLastestWork(Long userId, Integer page) {
        var middleResult = illustrationService.getIllustrationSortedByTimeWithPagination(page);
        var result = new ArrayList<BriefIllustrationInfo>();
        for (var i : middleResult) {

    
            User author = userService.getById(i.getAuthorId());
            var url = fileService.convertToOnlinePath(illustrationCollectionService.getCollectionByIllustrationId(i.getId()).get(0).getImageUrl());
            boolean isLiked = likeIllustrationService.findLikeIllustration(userId, i.getId()) == null ? false : true;


            result.add(0, new BriefIllustrationInfo(i.getId(), i.getTitle(), url, new BriefUserInfo(author.getId(), author.getNickname(), author.getProfileImg() == null ? null : fileService.convertToOnlinePath(author.getProfileImg())), isLiked));
        }
        return result;
    }

    
       
}
